/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2009>  <Asaf Yarkoni asaf@yarkoni.net>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using System.Windows.Forms;
using MyPhotoIndex.Utilities;
using MyPhotoIndex.Interfaces;
using System.Runtime.InteropServices;
using MyPhotoIndex.Interfaces.Imaging;
using System.Threading;
using System.IO;

namespace MyPhotoIndex.Controls
{
    public enum ThumbnailIcon { Invalid = 0, Tag = 1, Info = 2, Rating = 3, Play = 4, Stop = 5, CheckBox = 6, Categories = 7, DateText = 8 }
    public enum ThumbnailTextInfo { DateTaken = 0, DateDigitized = 1, FileName = 2 }

    [Serializable]
    public class Thumbnail : ImageInstance
    {
        static Image ms_checkBoxCheckedImage = Resources.Resources.CheckBox_Checked;
        static Image ms_checkBoxUnCheckedImage = Resources.Resources.CheckBox_UnChecked;
        static Image ms_infoIconImage = new Bitmap(Resources.Resources.info_icon, 16, 16);
        static Image ms_tagIconImage = new Bitmap(Resources.Resources.Tag_16, 16, 16);
        static Image ms_tagInvertedIconImage = new Bitmap(Resources.Resources.Tag_16_Inverted, 16, 16);
        static Image ms_star16Image = new Bitmap(Resources.Resources.star_16, 16, 16);
        static Image ms_starConfig16Image = new Bitmap(Resources.Resources.star_config_16, 16, 16);
        static Image ms_playImage = new Bitmap(Resources.Resources.Play, 16, 16);
        static Image ms_playImageDisabled = new Bitmap(Resources.Resources.Play_disabled, 16, 16);
        static Image ms_stopImage = new Bitmap(Resources.Resources.stop, 16, 16);
        static Image ms_stopImageDisabled = new Bitmap(Resources.Resources.stop_disabled, 16, 16);
        static Image ms_fileLockImage = new Bitmap(Resources.Resources.file_lock_24, 24, 24);
        static Image ms_fileMissingImage = new Bitmap(Properties.Resources.file_missing_24, 24, 24);
        static Image ms_imageVersionImage = new Bitmap(Resources.Resources.branch_24, 24, 24);
        static Color ms_borderColor = Color.FromArgb(79, 94, 113);
        static Color ms_selectedBorderColor = Color.FromArgb(124, 212, 124);
        static Color ms_selectedNonFocusedColor = Color.FromArgb(124, 200, 124);
        static Color[] ms_gradiantBorderColors = new Color[]{Color.FromArgb(156, 164, 175), 
                                                                Color.FromArgb(170, 179, 191),
                                                                Color.FromArgb(184, 194, 207), 
                                                                Color.FromArgb(199, 209, 223),
                                                                Color.FromArgb(213, 224, 239)};
        private static Font ms_imageSourceLabelFont = new Font("verdana", 10);
        private static Font m_font = new Font("family", 8, FontStyle.Bold);

        private MyPhotoIndexThumbnailViewer m_parent;
        private CategoryRenderer m_categoryRenderer;

        private bool m_showImageInfo;
        private bool m_showInfoIcons;
        private bool m_showCheckBoxes;
        private bool m_videoPlaying = false;

        private Rectangle m_ratingStarsRect = Rectangle.Empty;
        private Rectangle m_playIconRect = Rectangle.Empty;
        private Rectangle m_stopIconRect = Rectangle.Empty;
        private Rectangle m_checkBoxRect = Rectangle.Empty;
        private Rectangle m_categoriesRect = Rectangle.Empty;
        private Rectangle m_dateTextRect = Rectangle.Empty;
        private Rectangle m_displayRectangle = Rectangle.Empty;

        private static TextBox m_captionTextBox = new TextBox();

        public Thumbnail(IImageData imageData, Rectangle imageRect, Rectangle frameRect, MyPhotoIndexThumbnailViewer parent)
            :
            base(imageData, imageRect, frameRect)
        {
            m_parent = parent;
            m_captionTextBox.Multiline = true;
        }

        public MyPhotoIndexThumbnailViewer Parent
        {
            get { return m_parent; }
        }

        public Rectangle DisplayRectangle
        {
            get { return m_displayRectangle; }
            set { m_displayRectangle = value; }
        }

        public bool VideoPlaying
        {
            get { return m_videoPlaying; }
            set { m_videoPlaying = value; }
        }

        public bool ShowImageInfo
        {
            get { return m_showImageInfo; }
            set { m_showImageInfo = value; }
        }

        public CategoryRenderer CategoryRenderer
        {
            get { return m_categoryRenderer; }
            set { m_categoryRenderer = value; }
        }

        internal void DrawImage(Graphics graphics, bool selected, bool useCheckBoxes, bool checkedValue, bool showInfoIcons, bool showDetails)
        {
            try
            {
                if (m_showImageInfo == false)
                {
                    lock (this.ImageData.SyncLock)
                    {
                        Image image = this.Image;

                        Rectangle drawingRect = ImageDrawingRect;

                        if (image != null &&
                            drawingRect.Width > 0 && drawingRect.Height > 0)
                        {
                            using (Image newImage = new Bitmap(image, drawingRect.Size))
                            {
                                if (m_displayRectangle == Rectangle.Empty)
                                {
                                    graphics.DrawImageUnscaled(newImage, drawingRect);
                                }
                                else
                                {
                                    graphics.DrawImage(newImage, drawingRect, m_displayRectangle, GraphicsUnit.Pixel);
                                }
                            }

                            if (ImageData.Encrypted == true)
                            {
                                Rectangle ImageIconRect = drawingRect;
                                graphics.DrawImageUnscaled(ms_fileLockImage, ImageIconRect);
                            }

                            if (ImageData.VersionsCount > 0)
                            {
                                Rectangle imageIconRect = drawingRect;
                                if (ImageData.Encrypted == true)
                                {
                                    imageIconRect.Offset(30, 0);
                                }

                                graphics.DrawImageUnscaled(ms_imageVersionImage, imageIconRect);
                            }

                            if (ImageData.LinkStatus == ImageLinkStatus.Invalid)
                            {
                                Rectangle ImageIconRect = drawingRect;
                                graphics.DrawImageUnscaled(ms_fileMissingImage, ImageIconRect);
                                if (string.IsNullOrEmpty(ImageData.SourceLabel) == false)
                                {
                                    graphics.DrawString(ImageData.SourceLabel, ms_imageSourceLabelFont, Brushes.White, new PointF(ImageIconRect.Location.X + 22, ImageIconRect.Location.Y + 8));
                                }
                            }
                        }
                        else
                            if (drawingRect.Width > 0 && drawingRect.Height > 0)
                            {
                                graphics.DrawImage(m_parent.ImageMissingImage, ImageDrawingRect);
                            }
                    }
                }
                else
                {
                    DrawImageInfoCaption(graphics);
                }
            }
            catch (ArgumentNullException anex)
            {
                String imageInfo = this.ImageData.ToString();
                Logger.Log(imageInfo, anex);
            }
            catch (Exception ex)
            {
                String imageInfo = this.ImageData.ToString();
                Logger.Log(imageInfo, ex);
            }

            try
            {
                DrawFrame(graphics, selected, useCheckBoxes, checkedValue, showInfoIcons, showDetails);
            }
            catch (Exception ex)
            {
                Logger.Log(ex);
            }
        }

        private void DrawImageInfoCaption(Graphics graphics)
        {
            using (Bitmap bmp = new Bitmap(ImageDrawingRect.Width, ImageDrawingRect.Height))
            {
                lock (m_captionTextBox)
                {
                    m_captionTextBox.Text = this.ImageData.Comment;
                    m_captionTextBox.SetBounds(0, 0, ImageDrawingRect.Width, ImageDrawingRect.Height);
                    m_captionTextBox.DrawToBitmap(bmp, new Rectangle(0, 0, ImageDrawingRect.Width, ImageDrawingRect.Height));

                    graphics.FillRectangle(Brushes.WhiteSmoke, ImageDrawingRect);
                    graphics.DrawImageUnscaled(bmp, ImageDrawingRect.Location);
                }
            }
        }

        internal void DrawFrame(Graphics graphics, bool selected,
                bool showCheckBoxes, bool checkedValue, bool showInfoIcons,
                        bool showDetails)
        {
            Color seletedColor = (m_parent.Focused ? ms_selectedBorderColor : ms_selectedNonFocusedColor);

            using (Pen borderPen = new Pen(selected ? seletedColor : ms_borderColor))
            {
                graphics.DrawRectangle(borderPen, ImageDrawingRect);

                if (selected == true)
                {
                    Rectangle bordersRect = Rectangle.Inflate(ImageDrawingRect, 1, 1);
                    graphics.DrawRectangle(borderPen, bordersRect);

                    bordersRect = Rectangle.Inflate(ImageDrawingRect, 2, 2);
                    graphics.DrawRectangle(borderPen, bordersRect);
                }
            }

            Color[] borderColors = new Color[]{selected? seletedColor : ms_gradiantBorderColors[0], 
                                                selected? seletedColor : ms_gradiantBorderColors[1],
                                                    ms_gradiantBorderColors[2],
                                                        ms_gradiantBorderColors[3],
                                                            ms_gradiantBorderColors[4]};

            int borderOffset = 1;

            for (int colorIdx = 0; colorIdx < borderColors.Length; colorIdx++)
            {
                Color color = borderColors[colorIdx];

                using (Pen borderPen = new Pen(color))
                {
                    Point borderStart = new Point(ImageDrawingRect.X, ImageDrawingRect.Bottom + borderOffset);
                    Point borderEnd = new Point(ImageDrawingRect.Right + borderOffset, ImageDrawingRect.Bottom + borderOffset);

                    graphics.DrawLine(borderPen, borderStart, borderEnd);

                    borderStart = new Point(ImageDrawingRect.Right + borderOffset, ImageDrawingRect.Top);
                    borderEnd = new Point(ImageDrawingRect.Right + borderOffset, ImageDrawingRect.Bottom + borderOffset);

                    graphics.DrawLine(borderPen, borderStart, borderEnd);
                }

                ++borderOffset;
            }

            m_showInfoIcons = false;
            m_showCheckBoxes = false;
            if (showDetails == true)
            {
                m_showCheckBoxes = showCheckBoxes;
                if (showCheckBoxes == true)
                {
                    DrawCheckBox(graphics, checkedValue);
                }

                m_showInfoIcons = showInfoIcons;
                if (m_showInfoIcons == true)
                {
                    DrawInfoIcons(graphics);
                }
            }
        }

        internal void DrawCheckBox(Graphics graphics, bool checkedValue)
        {
            Image checkBoxImage = checkedValue ? ms_checkBoxCheckedImage : ms_checkBoxUnCheckedImage;
            m_checkBoxRect = new Rectangle(new Point(FirstIconRectangle.Right - checkBoxImage.Width + 5, FirstIconRectangle.Bottom - 12), checkBoxImage.Size);
            graphics.DrawImage(checkBoxImage, m_checkBoxRect.Location);
        }

        internal void DrawInfoIcons(Graphics graphics)
        {
            Rectangle firstIconRect = FirstIconRectangle;
            if (firstIconRect.IsEmpty == true)
            {
                return;
            }

            int numOfTags = base.ImageData.Tags.Length;
            if (numOfTags > 0)
            {
                graphics.DrawImageUnscaled(ms_tagIconImage, firstIconRect.Location);
                firstIconRect.X -= (firstIconRect.Width + 5);
            }

            graphics.DrawImageUnscaled(ms_infoIconImage, firstIconRect.Location);

            m_ratingStarsRect = firstIconRect;
            firstIconRect.X -= (firstIconRect.Width);

            if (ImageData.Rating > 0)
            {
                for (int ii = 0; ii < ImageData.Rating; ii++)
                {
                    firstIconRect.X -= 5;
                    graphics.DrawImageUnscaled(ms_star16Image, firstIconRect.Location);
                }
            }
            else
            {
                firstIconRect.X -= 5;
                graphics.DrawImageUnscaled(ms_starConfig16Image, firstIconRect.Location);
            }

            int numOfStars = ImageData.Rating;
            if (numOfStars == 0)
            {
                numOfStars++;
            }

            m_ratingStarsRect.X = firstIconRect.X;
            m_ratingStarsRect.Width = (numOfStars * 8) + 5;


            m_categoriesRect = m_ratingStarsRect;
            m_categoriesRect.Width = 13;
            m_categoriesRect.Height = 13;
            m_categoriesRect.X -= 18;
            m_categoriesRect.Y += 2;

            if (m_categoryRenderer != null)
            {
                m_categoryRenderer.Render(graphics, m_categoriesRect, ImageData);
            }

            if (ImageData.IsVideo == true)
            {
                m_playIconRect = m_categoriesRect;
                m_playIconRect.X -= 1;
                m_playIconRect.X -= ms_playImage.Width;
                m_playIconRect.Y -= 1;
                m_playIconRect.Width = 14;
                m_playIconRect.Height = 14;
                graphics.DrawImageUnscaled(m_videoPlaying ? ms_playImageDisabled : ms_playImage, m_playIconRect.Location);

                m_stopIconRect = m_playIconRect;
                m_stopIconRect.X += 4;
                m_stopIconRect.X -= ms_playImage.Width;

                graphics.DrawImageUnscaled(m_videoPlaying ? ms_stopImage : ms_stopImageDisabled, m_stopIconRect.Location);
            }

            string infoString = string.Empty;
            switch (m_parent.ThumbnailTextInfoDisplayType)
            {
                case ThumbnailTextInfo.DateTaken:
                    DateTime dateTaken = ImageData.DateTaken;
                    infoString = dateTaken.ToString("d", Thread.CurrentThread.CurrentUICulture);
                    break;
                case ThumbnailTextInfo.DateDigitized:
                    DateTime dateDigitized = ImageData.DateDigitized;
                    infoString = dateDigitized.ToString("d", Thread.CurrentThread.CurrentUICulture);
                    break;
                case ThumbnailTextInfo.FileName:
                    infoString = Path.GetFileNameWithoutExtension(ImageData.FileName);
                    break;
                default:
                    break;
            }

            SizeF dateTextSize = graphics.MeasureString(infoString, m_font);

            Rectangle imageDrawingRect = FrameDrawingRect;
            m_dateTextRect.X = imageDrawingRect.X + 5;
            m_dateTextRect.Y = firstIconRect.Y + 2;
            m_dateTextRect.Width = (int)Math.Ceiling(dateTextSize.Width);
            m_dateTextRect.Height = (int)Math.Ceiling(dateTextSize.Height);

            Point start = m_dateTextRect.Location;
            graphics.DrawString(infoString, m_font, Brushes.Gray, start);
        }

        public Rectangle FirstIconRectangle
        {
            get
            {
                if (FrameDrawingRect.Width < 90)
                {
                    return new Rectangle();
                }

                Rectangle firstIconRect = Rectangle.Empty;
                Rectangle imageDrawingRect = ImageDrawingRect;
                //if (ImageAlgo.IsLandscapeImage(imageDrawingRect.Size))
                //{
                //    firstIconRect = new Rectangle(new Point(imageDrawingRect.Right - (ms_infoIconImage.Width / 2), FrameDrawingRect.Bottom - 20), new Size(ms_infoIconImage.Width, ms_infoIconImage.Height));
                //}
                //else
                {
                    firstIconRect = new Rectangle(new Point(FrameDrawingRect.Right - (ms_infoIconImage.Width + 8), FrameDrawingRect.Bottom - 20), new Size(ms_infoIconImage.Width, ms_infoIconImage.Height));
                }

                return firstIconRect;
            }
        }

        public ThumbnailIcon GetThumbnailIconFromMousePos(Point mousePosition)
        {
            if (m_showInfoIcons == false)
            {
                if (m_checkBoxRect.Contains(mousePosition) == true)
                {
                    return ThumbnailIcon.CheckBox;
                }

                return ThumbnailIcon.Invalid;
            }

            Rectangle firstIconRect = FirstIconRectangle;
            if (firstIconRect.IsEmpty == true)
            {
                return ThumbnailIcon.Invalid;
            }

            int numOfTags = 0;
            if (base.ImageData.Tags != null)
            {
                numOfTags = base.ImageData.Tags.Length;
            }

            if (firstIconRect.Contains(mousePosition) == true)
            {
                if (numOfTags > 0)
                {
                    return ThumbnailIcon.Tag;
                }
                else
                {
                    return ThumbnailIcon.Info;
                }
            }

            firstIconRect.X -= (firstIconRect.Width + 5);
            if (firstIconRect.Contains(mousePosition) == true)
            {
                if (numOfTags > 0)
                {
                    return ThumbnailIcon.Info;
                }
            }

            if (m_ratingStarsRect.Contains(mousePosition) == true)
            {
                return ThumbnailIcon.Rating;
            }

            if (m_categoriesRect.Contains(mousePosition) == true)
            {
                return ThumbnailIcon.Categories;
            }

            if (m_playIconRect.Contains(mousePosition) == true)
            {
                return ThumbnailIcon.Play;
            }

            if (m_stopIconRect.Contains(mousePosition) == true)
            {
                return ThumbnailIcon.Stop;
            }

            if (m_dateTextRect.Contains(mousePosition) == true)
            {
                return ThumbnailIcon.DateText;
            }

            return ThumbnailIcon.Invalid;
        }

        public void RotateAnimation(int fromAngle, int toAngle)
        {
            Color borderColor = m_parent.BackColor;
            using (Graphics graphics = Graphics.FromHwnd(m_parent.Handle))
            {
                using (Brush borderBrush = new SolidBrush(borderColor))
                {
                    Rectangle bordersRect = Rectangle.Inflate(ImageDrawingRect, 6, 6);
                    graphics.FillRectangle(borderBrush, bordersRect);
                }

                //DrawFrame(graphics, false, ThumbnailSelectionMethod.Standard, m_showInfoIcons, true);


                Rectangle maxRect = m_parent.GetImageDrawingRect(base.ImageData.Id);
                ImageAlgo.RotateImageAnimation(graphics, Image, ImageDrawingRect, maxRect, fromAngle, toAngle, borderColor);
            }
        }

        public void FlashTagIcon(bool on)
        {
            using (Graphics graphics = Graphics.FromHwnd(m_parent.Handle))
            {
                Rectangle firstIconRect = FirstIconRectangle;
                if (firstIconRect.IsEmpty == true)
                {
                    return;
                }

                int numOfTags = base.ImageData.Tags.Length;
                if (numOfTags > 0)
                {
                    graphics.DrawImageUnscaled((on == true) ? ms_tagInvertedIconImage : ms_tagIconImage, firstIconRect.Location);
                }
            }
        }
    }
}
